home *** CD-ROM | disk | FTP | other *** search
- /*________________________________________________________________________________
- Debug.c: general purpose debugging code.
- ________________________________________________________________________________*/
-
- #include "Debug.h"
-
-
- #if DEBUG // [
-
- // avoid recursive calls with DebugTraps
- #include "DebugTrapsOff.h"
-
-
- static void AppendVariableName( const char *cVarName, StringPtr msg );
- static void AppendUserMsg( ConstStr255Param userMsg, StringPtr msg );
- static Boolean DebugGetErrorString( OSErr err, StringPtr errString);
-
-
- #if PRAGMA_MARK_SUPPORTED
- #pragma mark --- Utilities ---
- #endif
-
- /*________________________________________________________________________________
- Convert a number to a string.
-
- This version doesn't move memory, unlike the system version of NumToString,
- so it can be used safely anywhere.
- ________________________________________________________________________________*/
- static void
- NumToStringBase(
- long num,
- StringPtr outString,
- UInt16 base,
- Boolean isSigned)
- {
- Assert( base >= 2 && base <= 16, "\pNumToStringBase: illegal base");
- Assert( ( ! isSigned ) || base == 10, "\pNumToStringBase: signed only applies to base 10");
-
- if (num == 0)
- {
- outString[ 0 ] = 1;
- outString[ 1 ] = '0';
- }
- else
- {
- Boolean isNegative = false;
- UInt32 ulNum;
- UInt8 digitIndex;
- UInt8 tempBuffer[ 64 ]; // not a pascal string
- UInt8 *outPtr;
-
- // only base 10 is treated as signed. If so, convert using positive
- // number and remember that it's negative for later.
- if (num < 0 &&
- base == 10 &&
- isSigned)
- {
- isNegative = true;
- num = -num;
- }
-
- ulNum = (UInt32) num;
-
- // add digits in convenient (reverse) order
- outPtr = &tempBuffer[ 0 ];
- while ( ulNum > 0 )
- {
- UInt32 temp;
- UInt8 digitVal;
- static unsigned char sDigits[] = "0123456789ABCDEF";
-
- temp = ulNum/base;
- digitVal = ulNum - (temp * base);
-
- *outPtr++ = sDigits[ digitVal ];
-
- ulNum = temp;
- }
-
- if ( isNegative )
- {
- *outPtr++ = '-';
- }
-
- // reverse the digits so they're in the correct order
- outString[0] = outPtr - &tempBuffer[ 0 ];
-
- for (digitIndex = 1; digitIndex <= outString[0]; ++digitIndex)
- {
- outString[ digitIndex ] = *--outPtr;
- }
- }
- }
-
-
- /*________________________________________________________________________________
- Convert a number to a string (same as NumToString).
-
- Unlike the system version, does not move memory.
- ________________________________________________________________________________*/
- void
- DebugNumToString(
- long num,
- StringPtr string)
- {
- NumToStringBase( num, string, 10, TRUE);
- }
-
-
- static void
- CopyPString(
- ConstStr255Param srcStr,
- StringPtr destStr)
- {
- BlockMoveData( srcStr, destStr, 1UL + srcStr[ 0 ] );
- }
-
-
- static void
- AppendPString(
- ConstStr255Param appendStr,
- StringPtr destStr)
- {
- UInt8 lengthToAppend;
- #define kMaxStringLength (UInt16)255
-
- // if the new length would exceed the maximum string length, then
- // just append as much as possible
- lengthToAppend = appendStr[0];
- if ( lengthToAppend + (UInt32)destStr[0] > kMaxStringLength )
- lengthToAppend = kMaxStringLength - destStr[0];
-
- BlockMoveData( &appendStr[1], &destStr[destStr[0]+1], lengthToAppend);
- destStr[0] += lengthToAppend;
- }
-
-
-
- static void
- CToPString(
- const char *cString,
- StringPtr pString)
- {
- UInt32 length;
- UInt8 *curOut;
-
- length = 0;
- curOut = &pString[1];
- #define kMaxPascalStringLength 255
- while ( length < kMaxPascalStringLength )
- {
- if ( (curOut[length] = cString[length]) == 0)
- break;
- ++length;
- }
-
- pString[0] = length;
- }
-
-
-
-
- /*________________________________________________________________________________
- Example:
- GetDebugNumString( "\pThe value is", 229, result )
-
- returns the following string in 'result':
- "\pThe value is: 229"
- ________________________________________________________________________________*/
- void
- GetDebugNumString(
- ConstStr255Param failStr,
- long num,
- StringPtr msg)
- {
- Str32 numStr;
-
- CopyPString( failStr, msg);
- AppendPString( "\p: ", msg);
-
- DebugNumToString( num, numStr);
- AppendPString( numStr, msg);
- }
-
-
- #if PRAGMA_MARK_SUPPORTED
- #pragma mark -
- #endif
-
-
- /*________________________________________________________________________________
- Build an assert message using several strings.
-
- The awkward mix of C and Pascal strings is due to the fact that the C string
- was generated by the preprocessor whereas all the strings we work with are
- pascal strings.
-
- if passed "\pNIL ptr:", "theAddress\0", "\pMyRoutine()", construct:
- "\pNIL ptr: 'theAddress' [MyRoutine()]"
- ________________________________________________________________________________*/
- static void
- BuildBadAddressMsg(
- StringPtr result,
- ConstStr255Param prefix,
- const char * varName, // a null terminated C string
- ConstStr255Param suffix)
- {
- result[0] = 0;
-
- if ( prefix != nil )
- {
- AppendPString( prefix, result);
- }
-
- if ( varName != nil )
- {
- UInt8 temp[256];
-
- CToPString( varName, temp);
- AppendPString( "\p '", result);
- AppendPString( temp, result);
- AppendPString( "\p'", result);
- }
-
- if ( suffix != nil )
- {
- AppendPString( "\p [" /*]*/, result);
-
- AppendPString( suffix, result);
-
- AppendPString( /*[*/ "\p]", result);
- }
- }
-
-
- static void
- MemoryDummy(short dummy)
- {
- ++dummy;
- }
-
-
-
- /*________________________________________________________________________________
- Assert (and possibly crash) if the address is invalid
- This routine expressly does not return a value because part of its
- checks may result in a crash if an address is "extra" bogus.
- ________________________________________________________________________________*/
- void
- _AssertAddressIsValidAlign(
- const void *addr,
- const char *varName,
- UInt32 alignCount,
- ConstStr255Param msg)
- {
- Boolean aligned = FALSE;
- Str255 debugMsg;
-
- // a dererenced NIL pointer will result in the value at memory location zero
- Assert( addr != *(const void **)0, "\p_AssertAddressIsValidAlign: addr possibly a dereferenced NIL ptr");
-
- if ( IsNil( msg ) )
- {
- msg = "\p_AssertAddressIsValidAlign()";
- }
-
- if ( alignCount <= 1 )
- {
- Assert( alignCount > 0, "\p_AssertAddressIsValidAlign: alignment of 0 is illegal");
- aligned = TRUE;
- }
- else
- {
- aligned = (((UInt32)addr) % alignCount) == 0;
- }
-
- if ( ! aligned )
- {
- BuildBadAddressMsg( debugMsg, "\pMisaligned address:", varName, msg);
- DebugMsg( debugMsg );
- }
- else if ( ((UInt32)addr) < 256 )
- {
- if ( IsNil( addr ) )
- {
- BuildBadAddressMsg( debugMsg, "\pNIL address:", varName, msg);
- }
- else
- {
- BuildBadAddressMsg( debugMsg, "\pbad address < 256:", varName, msg);
- }
- DebugMsg( debugMsg );
- }
- else
- {
- /*________________________________________________________________________________
- make a memory reference to force a crash here if the handle is invalid
- It is better to force a crash here,
- rather than crashing in some obscure place in the ROM later
-
- call a dummy routine to hopefully prevent compiler from simply
- optimizing out our dereference.
- ________________________________________________________________________________*/
- MemoryDummy( *(short *)addr );
- }
-
- }
-
-
-
- /*________________________________________________________________________________
- Assert (and possibly crash) if the handle is invalid
- This routine expressly does not return a value because part of its
- checks may result in a crash if a handle is "extra" bogus.
- ________________________________________________________________________________*/
- void
- _AssertHandleIsValid(
- const void * theHandle, // void * avoids need to cast
- const char * varName, // a null terminated C string
- ConstStr255Param msg)
- {
- OSErr err;
- Str255 result;
-
- result[0] = 0;
-
- if ( IsNil( msg ) )
- {
- msg = "\pAssertHandleIsValid()";
- }
-
- _AssertAddressIsValidAlign( theHandle, varName, 4, msg);
-
-
- /*________________________________________________________________________________
- make a memory reference to force a crash here if the handle is invalid
- It is better to force a crash here,
- rather than crashing in some obscure place in the ROM later
-
- call a dummy routine to hopefully prevent compiler from simply
- optimizing out our dereference.
- ________________________________________________________________________________*/
- MemoryDummy( *(short *)theHandle );
-
- (void)HandleZone( (Handle) theHandle );
- err = MemError();
- if ( IsErr( err ) )
- {
- Str255 errStr;
-
- BuildBadAddressMsg( result, "\perror from HandleZone:", varName, msg);
-
- DebugGetErrorString( err, errStr );
- AppendPString( "\p: ", result);
- AppendPString( errStr, result);
-
- DebugMsg( result );
- }
-
- if ( IsntNil( *(Handle)theHandle ) )
- // check to see if we can get its size (if it has a master pointer)
- {
- (void)GetHandleSize( (Handle) theHandle );
- err = MemError();
- if ( IsErr( err ) )
- {
- Str255 errStr;
-
- BuildBadAddressMsg( result, "\perror from GetHandleSize:", varName, msg);
-
- DebugGetErrorString( err, errStr );
- AppendPString( "\p: ", result);
- AppendPString( errStr, result);
-
- DebugMsg( result );
- }
- }
- }
-
-
-
- static void
- AppendVariableName(
- const char *varName, // a null terminated C string
- StringPtr msg )
- {
- if ( IsntNil( varName ) )
- {
- Str255 tempStr;
-
- // append the variable name in quotes
- CToPString( varName, tempStr);
- AppendPString( "\p '", msg);
- AppendPString( tempStr, msg);
- AppendPString( "\p' ", msg);
- }
- }
-
-
- static void
- AppendUserMsg(
- ConstStr255Param userMsg,
- StringPtr msg
- )
- {
- if ( IsntNil( userMsg ) )
- {
- AppendPString( "\p <", msg);
- AppendPString( userMsg, msg);
- AppendPString( "\p>", msg);
- }
- }
-
-
-
- #if PRAGMA_MARK_SUPPORTED
- #pragma mark -
- #endif
-
-
-
-
- /*————————————————————————————————————————————————————————————————————————————————————————
- A table consists of an array of entries.
- ————————————————————————————————————————————————————————————————————————————————————————*/
- typedef struct OSErrStringTable
- {
- UInt16 numEntries;
- const DebugOSErrStringTableEntry *entries;
- } OSErrStringTable;
-
-
- /*————————————————————————————————————————————————————————————————————————————————————————
- Add an error string table to the list of tables. If the table is already
- in our list, do nothing.
- ————————————————————————————————————————————————————————————————————————————————————————*/
- #define kMaxErrStringTables 20
- static OSErrStringTable sOSErrStringTables[ kMaxErrStringTables ] = {0,};
- static UInt16 sNumOSErrStringTables = 0;
- void
- DebugAddOSErrStringTable(
- const DebugOSErrStringTableEntry *entries,
- UInt16 numEntries)
- {
- Boolean alreadyInList = FALSE;
- UInt16 tableIndex;
-
- // see if we already have the table in our list
- for( tableIndex = 0; tableIndex < sNumOSErrStringTables; ++tableIndex)
- {
- if ( sOSErrStringTables[tableIndex].entries == entries )
- {
- alreadyInList = TRUE;
- break;
- }
- }
-
- if ( ! alreadyInList )
- {
- if ( sNumOSErrStringTables < kMaxErrStringTables )
- {
- sOSErrStringTables[ sNumOSErrStringTables ].entries = entries;
- sOSErrStringTables[ sNumOSErrStringTables ].numEntries = numEntries;
- ++sNumOSErrStringTables;
- }
- else
- {
- DebugMsg("\pDebugAddOSErrStringTable(): no more tables available");
- }
- }
- }
-
-
-
- /*————————————————————————————————————————————————————————————————————————————————————————
- search an error table for an error code.
-
- return TRUE if found, FALSE otherwise. If found, return the index in 'foundIndex'
- ————————————————————————————————————————————————————————————————————————————————————————*/
- static Boolean
- SearchErrorTable(
- OSErr err,
- const OSErrStringTable *table,
- UInt16 * foundIndex)
- {
- UInt16 pairIndex;
- Boolean foundIt = FALSE;
-
- *foundIndex = 0;
-
- for( pairIndex = 0; pairIndex < table->numEntries; ++pairIndex)
- {
- if ( table->entries[ pairIndex ].err == err )
- {
- foundIt = TRUE;
- *foundIndex = pairIndex;
- break;
- }
- }
- return( foundIt );
- }
-
-
- // include standard error table
- #include "DebugOSErrStrings.inc"
-
- static void
- AddDefaultErrorStringTables()
- {
- static Boolean sAddedDefaultTables = FALSE;
-
- // add the default table to the list if it has not yet been added
- if ( ! sAddedDefaultTables )
- {
- sAddedDefaultTables = TRUE;
-
- DebugAddOSErrStringTable( sSystemErrorsTable,
- sizeof( sSystemErrorsTable ) / sizeof( sSystemErrorsTable[0] ));
- }
- }
-
-
- /*————————————————————————————————————————————————————————————————————————————————————————
- Get a pascal string corresponding to an error code.
-
- If a string was found, return true, otherwise return false and use a numeric code.
- ————————————————————————————————————————————————————————————————————————————————————————*/
- static Boolean
- DebugGetErrorString(
- OSErr err,
- StringPtr errString)
- {
- UInt16 tableIndex;
- Boolean haveString = false;
-
- AddDefaultErrorStringTables();
-
- errString[0] = 0;
-
- // search all error tables one-by-one until we find a match
- for( tableIndex = 0; tableIndex < sNumOSErrStringTables; ++tableIndex)
- {
- const OSErrStringTable *table;
- UInt16 entryIndex;
-
- table = &sOSErrStringTables[tableIndex];
-
- if ( SearchErrorTable( err, table, &entryIndex) )
- {
- haveString = true;
- CToPString( table->entries[entryIndex].cString, errString);
- break;
- }
- }
-
- if ( StrLength( errString ) == 0 )
- {
- // just return the numeric code
- DebugNumToString( err, errString);
- }
-
- return( haveString );
- }
-
-
-
- /*————————————————————————————————————————————————————————————————————————————————————————
- Append a string of the following form:
- -34 (dskFulErr) [userMsg]
- ————————————————————————————————————————————————————————————————————————————————————————*/
- static void
- AppendRemainderOfErrString(
- OSErr err,
- StringPtr msgSoFar,
- ConstStr255Param optionalClientMsg)
- {
- Str255 errString;
-
- // msgSoFor looks like "\pAssertNoErr: "
-
- // append the numeric error code
- DebugNumToString( err, errString);
- AppendPString( errString, msgSoFar);
- AppendPString( "\p ", msgSoFar);
- // msgSoFor now "\pAssertNoErr: -34 "
-
-
- // if available, append the textual (non-numeric) error with parentheses
- if ( DebugGetErrorString( err, errString) )
- {
- AppendPString( "\p (", msgSoFar);
- AppendPString( errString, msgSoFar);
- AppendPString( "\p)", msgSoFar);
- // msgSoFor now "\pAssertNoErr: -34 (dskFulErr)"
- }
-
- // append any additional message
- if ( IsntNil( optionalClientMsg ) )
- {
- AppendPString( "\p [" /*]*/, msgSoFar);
- AppendPString( optionalClientMsg, msgSoFar);
- AppendPString( /*[*/ "\p]", msgSoFar);
- // msgSoFor now "\pAssertNoErr: -34 (dskFulErr) [optionalClientMsg]"
- }
- }
-
-
- /*————————————————————————————————————————————————————————————————————————————————————————
- drop into the debugger with an assert if 'err' is not 'noErr'
- ————————————————————————————————————————————————————————————————————————————————————————*/
- void
- AssertNoErr(
- OSErr err,
- ConstStr255Param optionalMsg)
- {
- #define IsCancelErr( err ) ( (err) == userCanceledErr )
-
- // don't report cancel errors
- if ( IsErr( err ) && ! IsCancelErr( err ) )
- {
- Str255 msg;
-
- CopyPString( "\pAssertNoErr: ", msg);
- AppendRemainderOfErrString( err, msg, optionalMsg);
- DebugStr( msg );
- }
- }
-
-
-
-
- #endif // ] DEBUG
-